home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / util / boot / BlizKick.lha / BlizKick / romupdatesplit.e < prev    next >
Text File  |  2000-09-04  |  15KB  |  568 lines

  1. -> FILE: ESrc:Own/romupdatesplit.e          REV: 5 --- split V44 rom update to executables
  2. /* History
  3.    0      Started in January 2000.
  4.    1      Quickly hacked up some ident code for BlizKick 1.20 beta.
  5.    2      15th Jan 2000: Added proper system detection. Added computer
  6.           specific switches. Use 'ALL' to emulate old way of operation.
  7.    3      Added CPU, FPU and NOBOARDCHECK switches.
  8.    4      18th Jan: Attnflags test was broken. Added support for some
  9.           future stuff. :)
  10.    5      28th Apr: Now generates neat comments for files by default,
  11.           can be turned off with NOCOMMENT/S. Bugfix: FROM is no longer
  12.           relative to TO.
  13. */
  14.  
  15.  
  16. /*
  17.   V44 SetPatch compatible "devs:AmigaOS ROM Update" file
  18.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  19.   by Harry "Piru" Sintonen. This information is 100% incorrect, or at
  20.   least you must assume so. you have been warned. :)
  21.  
  22.   STRUCTURE romfileheader,0
  23.   ULONG  numexecutables    ; number of valid executables included
  24.   ULONG  file_1_offset
  25.   ULONG  file_2_offset
  26.   ULONG  file_numexecutables_offset
  27.   ; there is no SIZEOF
  28.  
  29.   STRUCTURE exewrapper,0
  30.   ULONG  ew_reqflags    ; flagset
  31.   ULONG  ew_attnflags   ; attn flags bits that must be set for this module
  32.   ULONG  ew_boardid     ; if bit 0 is set, (manufacturer<<16|product) board must be found
  33.   ULONG  ew_unused      ; must be 0
  34.   LABEL  executable
  35.   ; there is no SIZEOF
  36.  
  37.   ; flags as of now
  38.   BITDEF  REQ,OCS_DENISE1,0
  39.   BITDEF  REQ,OCS_DENISE2,1
  40.   BITDEF  REQ,ECS_DENISE1,2
  41.   BITDEF  REQ,ECS_DENISE2,3
  42.   BITDEF  REQ,A3000,4
  43.   BITDEF  REQ,A600,5
  44.   BITDEF  REQ,A1200,8
  45.   BITDEF  REQ,A4000,9
  46.   BITDEF  REQ,A4000T,10
  47.   BITDEF  REQ,CD32,11
  48.  
  49.     scsi.device ->
  50.  
  51.     a300.ld.strip           A1200 IDE      IDE_scsidisk
  52.     a600.ld.strip           A600 IDE       IDE_scsidisk
  53.     a1000.ld.strip          A4000[T] IDE   IDE_scsidisk
  54.     a4000t.ld.strip         A4000T SCSI    A4000T_scsidisk.devuce
  55.     scsidisk.ld.strip       A3000[T]       scsidisk
  56.  
  57.     name: FileSystem.resource -> FILESYSRES
  58.     filesystem -> FILESYSTEM
  59. */
  60.  
  61.  
  62. OPT REG=5,RTD,020
  63.  
  64. MODULE 'dos/dos','dos/doshunks','exec/memory','exec/execbase',
  65.        'graphics/gfxbase','exec/execbase'
  66.  
  67. MODULE 'expansion'
  68.  
  69. ENUM ARG_FROM,ARG_A600,ARG_A1200,ARG_A3000,ARG_A4000I,ARG_A4000S,
  70.      ARG_CD32,ARG_CPU,ARG_FPU,ARG_NOBOARDCHECK,ARG_NOCOMMENT,
  71.      ARG_ALL,ARG_TO,NUMARGS
  72.  
  73. ENUM ER_OK,ER_PARAM,ER_INPUTFILE,ER_OUTPUTFILE,ER_READ,ER_SEEK,ER_WRITE,
  74.      ER_MEM,ER_CTRLC,ER_BADFILE
  75.  
  76.  
  77. ENUM UNKNOWN,ROMUPDIDENT,FILESYSTEM,FILESYSRES,RAMHANDLER,CONSOLEDEVICE,
  78.      UNKNOWNSCSI,UNKNOWNSCSIIDE,A300,A600,A1000,A4000,SCSIDISK,NUMOF
  79.  
  80. -> flags
  81. SET REQF_OCS_DENISE1,REQF_OCS_DENISE2,REQF_ECS_DENISE1,REQF_ECS_DENISE2,
  82.     REQF_A3000,REQF_A600,REQF_NONDEF6,REQF_NONDEF7,REQF_A1200,REQF_A4000,
  83.     REQF_A4000T,REQF_CD32
  84.  
  85.  
  86. DEF array[NUMARGS]:ARRAY OF LONG
  87. DEF ifh,ofh,buf[5]:ARRAY OF LONG
  88.  
  89. DEF counts[NUMOF]:ARRAY OF LONG
  90. DEF namebody[NUMOF]:ARRAY OF LONG
  91.  
  92. DEF attnflags=-1
  93.  
  94. DEF comment[80]:STRING
  95.  
  96. PROC main() HANDLE
  97.   DEF rdargs=0,oname=0:PTR TO CHAR,ioerr,ret
  98.   DEF r,pname[64]:STRING
  99.   DEF name,fsize
  100.   DEF lock=0,olddir,chdir=0,fib:PTR TO fileinfoblock
  101.   DEF cpu,fpu
  102.  
  103.   IF (KickVersion(37)=0) OR ((Int(Long(4)+296) AND AFF_68020)=0)
  104.     WriteF('Haha!\n'); RETURN 666
  105.   ENDIF
  106.  
  107.   r:='$VER: romupdatesplit 1.0.3 (28.4.00)'
  108.   FOR r:=0 TO NUMARGS-1; array[r]:=0; ENDFOR
  109.   IF (rdargs:=ReadArgs('FROM=FILE/A,A600/S,A1200/S,A3000/S,A4000I/S,A4000S/S,' +
  110.                        'CD32/S,CPU/K/N,FPU/K/N,NOBOARDCHECK/S,NOCOMMENT/S,' +
  111.                        'ALL/S,TO',
  112.                        array,NIL))=0 THEN Raise(ER_PARAM)
  113.  
  114.   name:=array[ARG_FROM]
  115.   fsize:=FileLength(name)
  116.   IF fsize<0 THEN Raise(ER_INPUTFILE)
  117.   IF (fsize<20) OR (fsize AND 3) THEN Raise(ER_BADFILE)
  118.  
  119.   IF (ifh:=Open(name,MODE_OLDFILE))=NIL THEN Raise(ER_INPUTFILE)
  120.  
  121.  
  122.   IF array[ARG_TO]
  123.     IF (lock:=Lock(array[ARG_TO],ACCESS_READ))=NIL THEN Raise(ER_PARAM)
  124.  
  125.     IF (fib:=AllocDosObject(DOS_FIB,NIL))=NIL THEN Raise(ER_PARAM)
  126.     ret:=Examine(lock,fib)
  127.     IF ret THEN r:=fib.direntrytype
  128.     FreeDosObject(DOS_FIB,fib)
  129.     IF ret=0 THEN Raise(ER_PARAM)
  130.     IF r<0
  131.       PrintF('TO must be a directory.\n')
  132.       Raise(ER_PARAM)
  133.     ENDIF
  134.  
  135.     olddir:=CurrentDir(lock); chdir:=1
  136.   ENDIF
  137.  
  138.   IF array[ARG_CPU]
  139.     cpu:=Long(array[ARG_CPU])
  140.     SELECT cpu
  141.       CASE 68000;
  142.         /* no-op */
  143.       CASE 68010;
  144.         attnflags:=attnflags OR AFF_68010
  145.       CASE 68020;
  146.         attnflags:=attnflags OR AFF_68010 OR AFF_68020
  147.       CASE 68030;
  148.         attnflags:=attnflags OR AFF_68010 OR AFF_68020 OR AFF_68030
  149.       CASE 68040;
  150.         attnflags:=attnflags OR AFF_68010 OR AFF_68020 OR AFF_68030 OR AFF_68040
  151.       CASE 68060;
  152.         attnflags:=attnflags OR AFF_68010 OR AFF_68020 OR AFF_68030 OR AFF_68040 OR $80
  153.       DEFAULT;
  154.         PrintF('bad CPU number \d\n',cpu)
  155.         Raise(ER_PARAM)
  156.     ENDSELECT
  157.   ENDIF
  158.   IF array[ARG_FPU]
  159.     fpu:=Long(array[ARG_FPU])
  160.     SELECT fpu
  161.       CASE 68881;
  162.         attnflags:=attnflags OR AFF_68881
  163.       CASE 68882;
  164.         attnflags:=attnflags OR AFF_68881 OR AFF_68882
  165.       CASE 68040;
  166.         attnflags:=attnflags OR AFF_68881 OR AFF_68882 OR AFF_FPU40
  167.       CASE 68060;
  168.         -> there's no AFF_FPU060
  169.         attnflags:=attnflags OR AFF_68881 OR AFF_68882 OR AFF_FPU40
  170.       DEFAULT;
  171.         PrintF('bad FPU number \d\n',fpu)
  172.         Raise(ER_PARAM)
  173.     ENDSELECT
  174.   ENDIF
  175.  
  176.  
  177.   r:=0
  178.   IF array[ARG_A600] THEN r++
  179.   IF array[ARG_A1200] THEN r++
  180.   IF array[ARG_A3000] THEN r++
  181.   IF array[ARG_A4000I] THEN r++
  182.   IF array[ARG_A4000S] THEN r++
  183.   IF array[ARG_CD32] THEN r++
  184.  
  185.   IF r>1
  186.     PrintF('specify only one of A600, A1200, A3000, A4000I, A4000S or CD32\n')
  187.     Raise(ER_PARAM)
  188.   ENDIF
  189.  
  190.   IF array[ARG_ALL] AND r
  191.     PrintF('specify only ALL or specific machine type\n')
  192.     Raise(ER_PARAM)
  193.   ENDIF
  194.  
  195.   IF array[ARG_ALL] AND (array[ARG_CPU] OR array[ARG_FPU] OR
  196.                          array[ARG_NOBOARDCHECK])
  197.     PrintF('you must not use CPU, FPU and/or NOBOARDCHECK with ALL\n')
  198.     Raise(ER_PARAM)
  199.   ENDIF
  200.  
  201.  
  202.   split(ifh,fsize)
  203.  
  204. EXCEPT DO
  205.   IF (exception="NEW") OR (exception="MEM") THEN exception:=ER_MEM
  206.  
  207.   IF exception
  208.     IF ioerr:=IoErr()
  209.       GetProgramName(pname,StrMax(pname)-1); PrintFault(ioerr,pname)
  210.     ENDIF
  211.     PrintF('Error \d: \s\n',exception,
  212.            ListItem(['','argument error','could not open input file',
  213.                     'could not open output file','read error',
  214.                     'seek error','write error','no memory','break',
  215.                     'bad file format'
  216.                     ],exception))
  217.     ret:=RETURN_ERROR
  218.   ELSE
  219.     ret:=RETURN_OK
  220.   ENDIF
  221.  
  222.   IF chdir THEN CurrentDir(olddir)
  223.   IF lock THEN UnLock(lock)
  224.  
  225.   IF ifh THEN Close(ifh)
  226.   IF ofh THEN Close(ofh)
  227.   IF exception AND oname THEN DeleteFile(oname)
  228.  
  229.   IF rdargs THEN FreeArgs(rdargs)
  230. ENDPROC ret
  231.  
  232.  
  233. PROC extractthis(head:PTR TO LONG)
  234.   DEF cdui,card,a3000,a4000,ncrscsi,mlisa=0,hrdenise=0,
  235.       gfxb:PTR TO gfxbase,flags,mask=0,attnf,af,
  236.       execb:PTR TO execbase,lib,manu,prod,exp
  237.  
  238.   IF array[ARG_ALL] THEN RETURN TRUE
  239.  
  240.   -> flag test
  241.  
  242.   flags:=head[]
  243.  
  244.   IF flags AND $F3F
  245.  
  246.     gfxb:=gfxbase
  247.  
  248.     Forbid()
  249.     IF (cdui:=FindResident('cdui.library'))
  250.       IF (cdui<$f80000) OR (cdui>$ffffff)
  251.         cdui:=0
  252.       ENDIF
  253.     ENDIF
  254.     card:=FindResident('card.resource')
  255.     a3000:=FindResident('A3000 bonus')
  256.     a4000:=FindResident('A4000 bonus')
  257.     ncrscsi:=FindResident('NCR scsi.device')
  258.     Permit()
  259.     
  260.     IF (gfxb.chiprevbits0 AND GFXF_AA_MLISA)
  261.       mlisa:=1
  262.     ENDIF
  263.     IF (gfxb.chiprevbits0 AND GFXF_HR_DENISE)
  264.       hrdenise:=1
  265.     ENDIF
  266.  
  267.     IF a4000
  268.       IF ncrscsi
  269.         mask:=REQF_A4000T
  270.       ELSE
  271.         mask:=REQF_A4000
  272.       ENDIF
  273.     ELSE
  274.       IF a3000
  275.         mask:=REQF_A3000
  276.       ELSEIF cdui 
  277.         mask:=REQF_CD32
  278.       ELSEIF card
  279.         IF mlisa
  280.           mask:=REQF_A1200
  281.         ELSE
  282.           mask:=REQF_A600
  283.         ENDIF
  284.       ELSEIF hrdenise
  285.         mask:=REQF_ECS_DENISE1 OR REQF_ECS_DENISE2
  286.       ELSE
  287.         mask:=REQF_OCS_DENISE1 OR REQF_OCS_DENISE2
  288.       ENDIF
  289.     ENDIF
  290.  
  291.     IF array[ARG_A600]
  292.       mask:=REQF_A600
  293.     ELSEIF array[ARG_A1200]
  294.       mask:=REQF_A1200
  295.     ELSEIF array[ARG_A3000]
  296.       mask:=REQF_A3000
  297.     ELSEIF array[ARG_A4000I]
  298.       mask:=REQF_A4000
  299.     ELSEIF array[ARG_A4000S]
  300.       mask:=REQF_A4000T
  301.     ELSEIF array[ARG_CD32]
  302.       mask:=REQF_CD32
  303.     ENDIF
  304.     
  305.     IF (flags AND mask)=0 THEN RETURN FALSE
  306.   ENDIF
  307.  
  308.   -> attnflags test
  309.  
  310.   IF attnf:=head[2] AND $FFFF
  311.     execb:=execbase
  312.     IF attnflags<>-1
  313.       af:=attnflags
  314.     ELSE
  315.       IF attnf AND $80
  316.         -> 060 attnflag required... make sure
  317.         -> 68060.library gets loaded...
  318.         IF execb.attnflags AND AFF_68040
  319.           IF (lib:=OpenLibrary('68060.library',0))
  320.             CloseLibrary(lib)
  321.           ENDIF
  322.         ENDIF
  323.       ENDIF
  324.       af:=execb.attnflags
  325.     ENDIF
  326.  
  327.     IF (attnf AND af)=0 THEN RETURN FALSE
  328.  
  329.   ENDIF
  330.  
  331.  
  332.   -> manu/prod test
  333.   IF array[ARG_NOBOARDCHECK]=0
  334.     IF head[2] AND 1
  335.       exp:=0
  336.       IF (expansionbase:=OpenLibrary('expansion.library',37))
  337.         manu:=Shr(head[2],16) AND $0FFFF
  338.         prod:=head[2] AND $0FFFF
  339.         exp:=FindConfigDev(NIL,manu,prod)
  340.         CloseLibrary(expansionbase)
  341.       ENDIF
  342.       IF exp=0 THEN RETURN FALSE
  343.     ENDIF
  344.   ENDIF
  345.  
  346. ENDPROC TRUE
  347.  
  348.  
  349. PROC getfiletype(ifh,offs,head:PTR TO LONG)
  350.   DEF buf[2048]:ARRAY OF CHAR,r,wpt:PTR TO INT,
  351.       name:PTR TO CHAR,idstring:PTR TO CHAR,len,hunk0,pos
  352.  
  353.   IF Seek(ifh,offs,OFFSET_BEGINNING)<0 THEN Raise(ER_SEEK)
  354.   len:=Read(ifh,buf,2047)
  355.   IF len<30 THEN Raise(ER_READ)
  356.   buf[2047]:=0; buf[len]:=0
  357.   IF Seek(ifh,offs,OFFSET_BEGINNING)<0 THEN Raise(ER_SEEK)
  358.  
  359.   IF Long(buf)<>HUNK_HEADER THEN Raise(ER_BADFILE)
  360.   IF Long(buf+4) THEN Raise(ER_BADFILE)
  361.  
  362.   hunk0:=buf+28+Shl(Long(buf+8),2); IF hunk0>=(buf+2048) THEN Raise(ER_BADFILE)
  363.  
  364.   len:=len-(hunk0-buf); IF len<26 THEN Raise(ER_BADFILE)
  365.  
  366.   wpt:=hunk0
  367.   FOR r:=0 TO Shr(len-26,1)
  368.     IF (wpt[]++=$4AFC)
  369.       IF Long(wpt)=(wpt-2-hunk0)
  370.         name:=hunk0+Long(wpt+12)
  371.         idstring:=hunk0+Long(wpt+16)
  372.         IF (name>buf) AND (name<(buf+2048)) AND
  373.            (idstring>buf) AND (idstring<(buf+2048))
  374.  
  375.           IF idstring[]
  376.             StrCopy(comment,idstring)
  377.           ELSEIF name[]
  378.             StrCopy(comment,name)
  379.           ELSE
  380.             comment[]:=0
  381.           ENDIF
  382.           -> strip linefeed and carriage returns
  383.           WHILE (pos:=StrLen(comment)-1)>0 AND ((comment[pos]=10) OR (comment[pos]=13))
  384.             comment[pos]:=0
  385.           ENDWHILE
  386.  
  387.           IF StrCmp(name,'AmigaOS ROM Update')
  388.             RETURN ROMUPDIDENT
  389.           ELSEIF StrCmp(name,'filesystem')
  390.             RETURN FILESYSTEM;
  391.           ELSEIF StrCmp(name,'FileSystem.resource')
  392.             RETURN FILESYSRES;
  393.           ELSEIF StrCmp(name,'ram-handler')
  394.             RETURN RAMHANDLER;
  395.           ELSEIF StrCmp(name,'console.device')
  396.             RETURN CONSOLEDEVICE;
  397.           ELSEIF StrCmp(name,'NCR scsi.device')
  398.             RETURN A4000;
  399.           ELSEIF StrCmp(name,'scsi.device')
  400.  
  401.             IF StrCmp(idstring,'scsidisk ',STRLEN)
  402.               RETURN SCSIDISK;
  403.             ELSEIF StrCmp(idstring,'IDE_scsidisk ',STRLEN)
  404.  
  405.               IF head[] AND REQF_A600
  406.                 RETURN A600;
  407.               ELSEIF head[] AND REQF_A1200
  408.                 RETURN A300;
  409.               ELSEIF head[] AND REQF_A4000
  410.                 RETURN A1000;
  411.               ENDIF
  412.  
  413.               RETURN UNKNOWNSCSIIDE;
  414.             ENDIF
  415.  
  416.             RETURN UNKNOWNSCSI;
  417.           ENDIF
  418.         ENDIF
  419.       ENDIF
  420.     ENDIF
  421.   ENDFOR
  422.  
  423. ENDPROC UNKNOWN
  424.  
  425. PROC split(ifh,fsize)
  426.   DEF num,seektable:PTR TO LONG,t,r,stack,
  427.       head[5]:ARRAY OF LONG,fname[32]:STRING,seg,size,
  428.       cnts[12]:STRING,type
  429.  
  430.   IF Read(ifh,{num},4)<>4 THEN Raise(ER_READ)
  431.  
  432.   IF num=HUNK_HEADER
  433.     PrintF('this file is already single executable!\n')
  434.     Raise(ER_PARAM)
  435.   ENDIF
  436.  
  437.   IF num>$ffff THEN Raise(ER_BADFILE)
  438.  
  439.   t:=Shl(num,2)
  440.   seektable:=NewR(t+4)
  441.  
  442.   IF Read(ifh,seektable,t)<>t THEN Raise(ER_READ)
  443.  
  444.   FOR r:=0 TO num-1
  445.     IF CtrlC() THEN Raise(ER_CTRLC)
  446.     IF seektable[r] AND 3 THEN Raise(ER_BADFILE)
  447.     IF Seek(ifh,seektable[r],OFFSET_BEGINNING)<0 THEN Raise(ER_SEEK)
  448.     IF Read(ifh,head,20)<>20 THEN Raise(ER_READ)
  449.     IF (Int(head+4)<>0) OR (head[3]<>0) OR (head[4]<>HUNK_HEADER)
  450.       Raise(ER_BADFILE)
  451.     ENDIF
  452.   ENDFOR
  453.  
  454.   FOR r:=0 TO NUMOF-1; counts[r]:=0; ENDFOR
  455.  
  456.   namebody[UNKNOWN]:='unknown'
  457.   namebody[ROMUPDIDENT]:='romupdate.idtag'
  458.   namebody[FILESYSTEM]:='FastFileSystem'
  459.   namebody[FILESYSRES]:='FileSystem.resource'
  460.   namebody[RAMHANDLER]:='ram-handler'
  461.   namebody[CONSOLEDEVICE]:='console.device'
  462.   namebody[UNKNOWNSCSI]:='unknown.ld.strip'
  463.   namebody[UNKNOWNSCSIIDE]:='unknown_ide.ld.strip'
  464.  
  465.   IF (array[ARG_ALL]=0) OR (array[ARG_A600] OR array[ARG_A1200] OR
  466.      array[ARG_A3000] OR
  467.      array[ARG_A4000I] OR array[ARG_A4000S] OR array[ARG_CD32])
  468.  
  469.     namebody[A300]:='scsi.device'
  470.     namebody[A600]:='scsi.device'
  471.     namebody[A1000]:='scsi.device'
  472.     namebody[A4000]:='NCR scsi.device'
  473.     namebody[SCSIDISK]:='scsi.device'
  474.  
  475.   ELSE
  476.  
  477.     namebody[A300]:='a300.ld.strip'
  478.     namebody[A600]:='a600.ld.strip'
  479.     namebody[A1000]:='a1000.ld.strip'
  480.     namebody[A4000]:='a4000.ld.strip'
  481.     namebody[SCSIDISK]:='scsidisk.ld.strip'
  482.  
  483.   ENDIF
  484.  
  485.   FOR r:=0 TO num-1
  486.     IF CtrlC() THEN Raise(ER_CTRLC)
  487.     IF Seek(ifh,seektable[r],OFFSET_BEGINNING)<0 THEN Raise(ER_SEEK)
  488.     IF Read(ifh,head,16)<>16 THEN Raise(ER_READ)
  489.  
  490.     size:=-16-seektable[r]+IF r<(num-1) THEN seektable[r+1] ELSE fsize
  491.     PutLong({filesize},size)
  492.     stack:=4096
  493.     IF seg:=InternalLoadSeg(ifh,NIL,[{readfunc},
  494.                                      {allocfunc},
  495.                                      {freefunc}]:LONG,{stack})=NIL
  496.       Raise(ER_BADFILE)
  497.     ENDIF
  498.     InternalUnLoadSeg(seg,{freefunc})
  499.  
  500.     IF extractthis(head)
  501.  
  502.       type:=getfiletype(ifh,seektable[r]+16,head)
  503.  
  504.       StringF(cnts,'.\d',counts[type])
  505.       StringF(fname,'\s\s',namebody[type],IF counts[type] THEN cnts ELSE '')
  506.  
  507.       PrintF('\d[02]: flags $\h[04]  offset $\h[06]  len $\h[06]  "\s"\n',
  508.              r,head[],seektable[r]+16,size,fname)
  509.  
  510.       IF Seek(ifh,seektable[r]+16,OFFSET_BEGINNING)<0 THEN Raise(ER_SEEK)
  511.       IF (ofh:=Open(fname,MODE_NEWFILE))=NIL THEN Raise(ER_OUTPUTFILE)
  512.       readwrite(size)
  513.       Close(ofh); ofh:=0
  514.  
  515.       IF array[ARG_NOCOMMENT]=0
  516.         IF comment[]
  517.           SetComment(fname,comment)
  518.         ENDIF
  519.       ENDIF
  520.  
  521.       counts[type]:=counts[type]+1
  522.  
  523.     ENDIF
  524.  
  525.   ENDFOR
  526.  
  527.   RETURN
  528. filesize:
  529.   LONG 0
  530. readfunc:
  531.   LEA    filesize(PC),A0
  532.   TST.L  (A0)
  533.   BGE.B  readok
  534.   MOVEQ  #0,D0
  535.   RTS
  536. readok:
  537.   CMP.L  (A0),D3
  538.   BLS.B  readskip
  539.   MOVE.L (A0),D3
  540. readskip:
  541.   SUB.L  D3,(A0)
  542.   JMP    Read(A6)
  543.  
  544. allocfunc:
  545.   MOVEQ  #0,D1
  546.   JMP    AllocMem(A6)
  547.  
  548. freefunc:
  549.   JMP    FreeMem(A6)
  550. ENDPROC
  551.  
  552. PROC readwrite(l)
  553.   DEF len,buf[8192]:ARRAY OF CHAR,buflen=8192
  554.   IF (len:=l AND $1FFFFFFF)=0 THEN RETURN
  555.  
  556.   IF len<buflen THEN buflen:=len
  557.  
  558.   WHILE len
  559.     IF CtrlC() THEN Raise(ER_CTRLC)
  560.     IF (l:=Read(ifh,buf,buflen))<1 THEN Raise(ER_READ)
  561.     IF Write(ofh,buf,l)<>l THEN Raise(ER_WRITE)
  562.     len:=len-l
  563.     IF len<buflen THEN buflen:=len
  564.   ENDWHILE
  565. ENDPROC
  566.  
  567.  
  568.